function mxElbowEdgeHandler(state)
{
	if (state != null)
	{
		this.state = state;
		this.graph = this.state.view.graph;
		this.graph.addMouseListener(this);
		this.marker = this.createMarker();
		this.init();
	}
};
mxElbowEdgeHandler.prototype = new mxEdgeHandler();
mxElbowEdgeHandler.prototype.constructor = mxElbowEdgeHandler;
mxElbowEdgeHandler.prototype.flipEnabled = true;
mxElbowEdgeHandler.prototype.doubleClickOrientationResource = (mxClient.language != 'none')
	? 'doubleClickOrientation' : '';
mxElbowEdgeHandler.prototype.createBends = function()
{
	var bends = [];
	var bend = new mxRectangleShape(new mxRectangle(), mxConstants.HANDLE_FILLCOLOR, mxConstants.HANDLE_STROKECOLOR);
	this.initBend(bend);
	bend.node.style.cursor = 'all-scroll';
	this.installListeners(bend, bends.length);
	bends.push(bend);
	bends.push(this.createVirtualBend());
	this.points.push(new mxPoint(0, 0));
	bend = new mxRectangleShape(new mxRectangle(), mxConstants.HANDLE_FILLCOLOR, mxConstants.HANDLE_STROKECOLOR);
	this.initBend(bend);
	bend.node.style.cursor = 'all-scroll';
	this.installListeners(bend, bends.length);
	bends.push(bend);
	return bends;
};
mxElbowEdgeHandler.prototype.createVirtualBend = function()
{
	var bend =
		new mxRectangleShape(new mxRectangle(0, 0, 1, 1), mxConstants.HANDLE_FILLCOLOR, mxConstants.HANDLE_STROKECOLOR);
	this.initBend(bend);
	var crs = this.getCursorForBend();
	bend.node.style.cursor = crs;

	if (this.graph.isCellBendable(this.state.cell))
	{
		this.installListeners(bend, 1);
	}
	else
	{
		bend.node.style.visibility = 'hidden';
	}
	var self = this;
	mxEvent.addListener(bend.node, 'dblclick', function(evt)
	{
		if (self.flipEnabled)
		{
			self.graph.flipEdge(self.state.cell, evt);
			mxEvent.consume(evt);
		}
	});
	var tip = this.doubleClickOrientationResource;
	tip = mxResources.get(tip) || tip;

	mxEvent.addListener(bend.node, 'mousemove', function(evt)
	{
		self.graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt, self.state, null, tip));
	});
	return bend;
};
mxElbowEdgeHandler.prototype.getCursorForBend = function()
{
	return (this.state.style[mxConstants.STYLE_EDGE] == mxEdgeStyle.TopToBottom
		|| this.state.style[mxConstants.STYLE_EDGE] == mxConstants.EDGESTYLE_TOPTOBOTTOM
		|| ((this.state.style[mxConstants.STYLE_EDGE] == mxEdgeStyle.ElbowConnector
			|| this.state.style[mxConstants.STYLE_EDGE] == mxConstants.EDGESTYLE_ELBOW)
			&& this.state.style[mxConstants.STYLE_ELBOW] == mxConstants.ELBOW_VERTICAL)) ? 'row-resize' : 'col-resize';
};
mxElbowEdgeHandler.prototype.convertPoint = function(point, gridEnabled)
{
	var scale = this.graph.getView().getScale();
	var tr = this.graph.getView().getTranslate();
	var origin = this.state.origin;

	if (gridEnabled)
	{
		point.x = this.graph.snap(point.x);
		point.y = this.graph.snap(point.y);
	}
	point.x = point.x / scale - tr.x - origin.x;
	point.y = point.y / scale - tr.y - origin.y;
};
mxElbowEdgeHandler.prototype.redrawInnerBends = function(p0, pe)
{
	var s = (this.graph.dialect == mxConstants.DIALECT_SVG) ? 3 : 4;
	var g = this.graph.getModel().getGeometry(this.state.cell);
	var pts = g.points;
	var pt = (pts != null) ? pts[0] : null;

	if (pt == null)
	{
		pt = new mxPoint(p0.x + (pe.x - p0.x) / 2, p0.y + (pe.y - p0.y) / 2);
	}
	else
	{
		pt = new mxPoint(this.graph.getView().scale * (pt.x + this.graph.getView().translate.x + this.state.origin.x),
			this.graph.getView().scale * (pt.y + this.graph.getView().translate.y + this.state.origin.y));
	}

	var bounds = new mxRectangle(pt.x - s, pt.y - s, 2 * s, 2 * s);

	if (this.labelShape.node.style.visibility != 'hidden' && mxUtils.intersects(bounds, this.labelShape.bounds))
	{
		s += 1;
		bounds = new mxRectangle(pt.x - s, pt.y - s, 2 * s, 2 * s);
	}
	this.bends[1].bounds = bounds;
	this.bends[1].reconfigure();
	this.bends[1].redraw();
};